#ifdef WITH_OPENGL
#include <windows.h>
#include "opengl.h"
#include <iostream>
#include <algorithm>

#include "opengl_debug.h"

#define FUNCTION_POINTERS_TO_ZERO(ret, name, type, params, paramscall) \
	fptr_##type##_t name = 0; \
	fptr_##type##_t orig_##name = 0;

#define LOAD_FUNCTION_ADDRESS(ret, name, type, params, paramscall) \
	name = (fptr_##type##_t)get_proc_address(#name); \
	if(name == 0){ /* if this remains zero we couldn't load this function pointer */ \
		l_FailedToLoad.push_back(#name " (" + l_ExtensionName + ")"); \
	}

#define EXTENSION_IS_IN_AVAILABLE_LIST(name) \
	{ \
		const std::string l_ExtensionName = #name; \
		bool l_HasFound = std::find(a_Available.begin(), a_Available.end(), #name) != a_Available.end(); \
		bool l_IsVersion = l_ExtensionName.find("VERSION") != std::string::npos; \
		if(l_HasFound || l_IsVersion){ \

#define END_EXTENSION_IS_IN_AVAILABLE_LIST() } }

#define LOAD_FUNCTION_ADDRESSES_ORIG(ret, name, type, params, paramscall) \
	orig_##name = (fptr_##type##_t)get_proc_address(#name); \
	name = a_Debug ? wrapper_##name : orig_##name; \
	if(orig_##name == 0){ /* if this remains zero we couldn't load this function pointer */ \
		l_FailedToLoad.push_back(#name " (" + l_ExtensionName + ")"); \
	}

namespace{
	class gl_call_handler{
	public:
		gl_call_handler(const char *a_FunctionName){
			krryn::system::gl_call_manager::get_instance().call_made(a_FunctionName);
		}

		~gl_call_handler() {
			krryn::system::gl_call_manager::get_instance().call_ended();
		}
	};

#define WRAPPER_FUNCTION(ret, name, type, params, paramscall) \
	ret APIENTRY wrapper_##name params{ \
		gl_call_handler l_CallHandler___(#name); \
		return orig_##name paramscall; \
	} 

EXTENSION_SET(NAME_EMPTY, WRAPPER_FUNCTION, CONST_EMPTY, END_EMPTY)
}

// initialize all function pointers to 0
// in global namespace!
EXTENSION_SET(NAME_EMPTY, FUNCTION_POINTERS_TO_ZERO, CONST_EMPTY, END_EMPTY)

using namespace krryn::system_imp;

std::vector<std::string> opengl_helper::load_extensions(const std::vector<std::string> &a_Available, bool a_Debug){
	std::vector<std::string> l_FailedToLoad;

	// if an extension is found in a_Available,
	// then initialize it's function pointers using get_proc_address()
	EXTENSION_SET(EXTENSION_IS_IN_AVAILABLE_LIST, LOAD_FUNCTION_ADDRESSES_ORIG, CONST_EMPTY, END_EXTENSION_IS_IN_AVAILABLE_LIST);

	return l_FailedToLoad;
}

// we might want to move this one

void *opengl_helper::get_proc_address(const char *a_ProcName){
#ifdef _WIN32
	return (void*)wglGetProcAddress(a_ProcName);
#endif
}
#endif